package com.chrray.position.util.rsa;

import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA加密工具类
 *
 * @author sunziwen
 * 2018-07-31 20:27
 * @version 1.0
 **/
public class RSAUtil {
    /**
     * RSA密钥长度必须是64的倍数，在512~65536之间。默认是1024
     */
    public static final int KEY_SIZE = 2048;

    /**
     * 公钥
     */
    private static final String publickeyStr = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA" +
            "onWzmO5C887p8jdTezrrOXwkeVqX2vqbjHtXmjkKstTcgezL6tXIWhult12kXykh3NR+YoBPh/j2Z5sbFC5degqXyPV2aMXLRlpmFpvBZN5D" +
            "SEW/GWDwZyjLwfj/00iB0QZdq1o0rJg8M/enTUfZn7OcekY5aIncoPSprx+aW3eTpvfjfIid0Nri" +
            "ToAXvclrd96rRuNCy/IUeNkUwg8U1XzNcgcxT93Lb7r6tM923hHIiGe6TNqzWoT/mS/2F29VMUxS" +
            "/dR35btofOVcOFzgt/9LXpTzHZpLbw9a+AQBbhvL0z3GboFJx0l3dcvyx/SBOR+wiJ7JunMkGbRK" +
            "cjHNnQIDAQAB";
    /**
     * 私钥
     */
    private static final String privateKeyStr = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCidbOY7kLzzunyN1N7Ous5fCR5" +
            "Wpfa+puMe1eaOQqy1NyB7Mvq1chaG6W3XaRfKSHc1H5igE+H+PZnmxsULl16CpfI9XZoxctGWmYW" +
            "m8Fk3kNIRb8ZYPBnKMvB+P/TSIHRBl2rWjSsmDwz96dNR9mfs5x6Rjloidyg9KmvH5pbd5Om9+N8" +
            "iJ3Q2uJOgBe9yWt33qtG40LL8hR42RTCDxTVfM1yBzFP3ctvuvq0z3beEciIZ7pM2rNahP+ZL/YX" +
            "b1UxTFL91Hflu2h85Vw4XOC3/0telPMdmktvD1r4BAFuG8vTPcZugUnHSXd1y/LH9IE5H7CInsm6" +
            "cyQZtEpyMc2dAgMBAAECggEAeqI8u0GH2sEjigrHgqs8Kv2SDuUa4lrwlj/5JdrPP6U8+vqEB7Xu" +
            "8k4SbvNKA+dpv2fMK5DN+EcvwY+tBjPlrh1W7ISWKIq+YlIU5BYZC4pX4bN8iKzLbCO4g6jxfE0s" +
            "aVvT02hZgLu+HkBg0w5csZgEk6x043vFxt5JRH+npkjOjDp4zQ2cZnQJPXc2jT9baCnOWDCGU+6c" +
            "6+tESgEVMWesp3K0PDP4r6oRIipqCh9rWKUWIGwrv8YEQ0rZVAPZj3Oa2FW5sVOMadaTNSL+tkIl" +
            "Eer7CVEJmFzV0sp2Gw8GuQFVScGusvH8EkUxsQ+h9HYs8QUn5MnEEFlLQCjSRQKBgQDOZo5Dy2O1" +
            "ucFw8mcblII6BJxyZxNdPF1Qtrod/rq75SM2BS4rPVgZ7jIaDbOmO9yIw2ALLqk84SWLnfIGauZf" +
            "zyFelgriKKxpoO3MQ1aQb0jNvNl/+qvJm9V8ysnp9MQ8KjL9C7nm0O40N53CL0BuTyq8lTbJzP80" +
            "EjjV/iDuQwKBgQDJf/lTkEL9gMVK6fip1sW6WHPPJNFrrCa1eSVKo5yMtwJe7TiXtgHLduQ5J8FY" +
            "AehNpzX71LnLu8q/ANnNN0zV14EeL8iKGvv0LTNHWLcUIaZALRaD5VthDngyXywQQKWU/Xps2GlR" +
            "UC0ejXdwR+M/LvIoDzxMpg8ClIIAxlLGnwKBgB3VgyDXiF0fMY/i6fZ5m+1I91guAAWNESv2jaaC" +
            "SHmaYGGRlB/Z6R8uZ/2OF3ai1njKTNqw7vOG08d/mBlHYG9e4ELsyzvvhyRph5Xr8dpEy7A5aPLv" +
            "x98HcG9uXIs9vxO3QdGD3WY4swXHOD12WQjY1qOVqeq3f/gF3kNITXhDAoGAKhm4AVKp/Id0MWPT" +
            "VcEPDRFAGS6rJuEQMWh/dynaIrh2IVlVMrWPiHBt3NdGmVnErLzcFaLrsvqosOG/oBYG0sM1MhZv" +
            "wxNCQ1FSXnzVu7oQH2aMRsCcKBo62ONztG2daxTPCIDq+FdVJgYOx4HtpBzt8ZrFUYp8pmBbDUhi" +
            "sScCgYBnJlSzhW3y10d6kEXFOEeYX29HOpC0BLMy+EWHOMeXyRo751ivrUbnUVqFncOK0wTn0FRz" +
            "02GCyAW9cy6wetiMSQ+nL6zArI13O0NJOyfUy/gucUl8a43i2BoYFfaoWFEu/f2pF3Q8vZSHIrMa" +
            "ZRDu6MGQ0/o3qq8ZfgzIFcZypg==";

    /**
     * 获取RSA公私钥匙对
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static KeyPair getKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }

    /**
     * 获取公钥(base64编码)
     *
     * @param keyPair
     * @return
     */
    public static String getPublicKey(KeyPair keyPair) {
        PublicKey publicKey = keyPair.getPublic();
        byte[] bytes = publicKey.getEncoded();
        return byte2Base64(bytes);
    }

    /**
     * 获取私钥(Base64编码)
     *
     * @param keyPair
     * @return
     */
    public static String getPrivateKey(KeyPair keyPair) {
        PrivateKey privateKey = keyPair.getPrivate();
        byte[] bytes = privateKey.getEncoded();
        return byte2Base64(bytes);
    }

    /**
     * 将Base64编码后的公钥转换成PublicKey对象
     *
     * @param pubStr
     * @return
     * @throws Exception
     */
    public static PublicKey string2PublicKey(String pubStr) throws Exception {
        byte[] keyBytes = base642Byte(pubStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 将Base64编码后的私钥转换成PrivateKey对象
     *
     * @param priStr
     * @return
     * @throws Exception
     */
    public static PrivateKey string2PrivateKey(String priStr) throws Exception {
        byte[] keyBytes = base642Byte(priStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 公钥加密
     *
     * @param content
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] publicEncrypt(byte[] content, PublicKey publicKey) throws Exception {
        int segmentSize = KEY_SIZE / 8 - 11;
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        //byte[] bytes = cipher.doFinal(content);
        byte[] resultBytes = null;
        if (segmentSize > 0)
            resultBytes = cipherDoFinal(cipher, content, segmentSize); //分段加密
        else
            resultBytes = cipher.doFinal(content);
        return resultBytes;
    }

    /**
     * 私钥解密
     *
     * @param content
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] privateDecrypt(byte[] content, PrivateKey privateKey) throws Exception {
        //Cipher cipher = Cipher.getInstance("RSA");
        //cipher.init(Cipher.DECRYPT_MODE, privateKey);
        //byte[] bytes = cipher.doFinal(content);
        int segmentSize = KEY_SIZE / 8;
        return decipher(content, privateKey, segmentSize);
    }

    /**
     * 分段解密
     *
     * @param contentBase64 密文
     * @param key           解密秘钥
     * @param segmentSize   分段大小（小于等于0不分段）
     * @return
     */
    public static  byte[] decipher(byte[] contentBase64, PrivateKey key, int segmentSize) {
        try {
            // Cipher负责完成加密或解密工作，基于RSA
            Cipher deCipher = Cipher.getInstance("RSA");
            // 根据公钥，对Cipher对象进行初始化
            deCipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decBytes = null;//deCipher.doFinal(srcBytes);
            if (segmentSize > 0)
                decBytes = cipherDoFinal(deCipher, contentBase64, segmentSize); //分段加密
            else
                decBytes = deCipher.doFinal(contentBase64);
            return decBytes;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 分段大小
     *
     * @param cipher
     * @param srcBytes
     * @param segmentSize
     * @return
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws IOException
     */
    public static byte[] cipherDoFinal(Cipher cipher, byte[] srcBytes, int segmentSize)
            throws IllegalBlockSizeException, BadPaddingException, IOException {
        if (segmentSize <= 0)
            throw new RuntimeException("分段大小必须大于0");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int inputLen = srcBytes.length;
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > segmentSize) {
                cache = cipher.doFinal(srcBytes, offSet, segmentSize);
            } else {
                cache = cipher.doFinal(srcBytes, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * segmentSize;
        }
        byte[] data = out.toByteArray();
        out.close();
        return data;
    }

    /**
     * 字节数组转Base64编码
     *
     * @param bytes
     * @return
     */
    public static String byte2Base64(byte[] bytes) {
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(bytes);
    }

    /**
     * Base64编码转数组
     *
     * @param base64Key
     * @return
     * @throws IOException
     */
    public static byte[] base642Byte(String base64Key) throws IOException {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        return base64Decoder.decodeBuffer(base64Key);
    }
    /**
     * @Description 加密的公共方法
     * @Author chen
     * @Date 2020/1/19
     * @Param str需要加密的字符串
     * @return
     */
    public static  String rsaEncryption(String str) {
        try {
            PublicKey publicKey = RSAUtil.string2PublicKey(publickeyStr);
            //加密accessToken
            byte[] bytes = RSAUtil.publicEncrypt(str.getBytes(), publicKey);
            //解决出现换行符
            String rsaEncryptionStr = Base64.encodeBase64String(bytes);
            System.err.println(rsaEncryptionStr);
            return  rsaEncryptionStr;
        } catch (Exception e) {
            System.err.println("加密错误信息：" + e);
            return null;
        }
    }
    /**
     * @Description 加密的公共方法
     * @Author chen
     * @Date 2020/1/19
     * @Param str需要解密的字符串
     * @return
     */
    public static  String rsaDecrypt(String str) {
        try {
            //decryptStr
            byte[] bytes = RSAUtil.privateDecrypt(RSAUtil.base642Byte(str), RSAUtil.string2PrivateKey(privateKeyStr));
            String decryptStr = new String(bytes);
            return  decryptStr;
        } catch (Exception e) {
            System.err.println("解密错误信息：" + e);
            return null;
        }
    }

}
